package reco.frame.tv.view;

import reco.frame.tv.R;
import reco.frame.tv.TvBitmap;
import reco.frame.tv.view.component.TvUtil;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.RelativeLayout;

/**
 * 专用于电视布局的RelativeLayout 子项获得焦点时 自动获得选中框效果 建议作为最外层容器使用
 * 
 * @author keYence
 * 
 */
public class TvRelativeLayoutAsGroup extends RelativeLayout {
	/**
	 * 光标
	 */
	private View cursor;
	private final String cursorTag = "TvRelativeLayoutAsGroup";
	/**
	 * 光标资源
	 */
	private int cursorRes;
	/**
	 * 可否缩放
	 */
	private boolean scalable;
	/**
	 * 放大比率
	 */
	private float scale;
	/**
	 * 光标飘移动画 默认无效果
	 */
	private int animationType;
	public final static int ANIM_DEFAULT = 0;// 无效果
	public final static int ANIM_TRASLATE = 1;// 平移
	/**
	 * 放大用时
	 */
	private int durationLarge;
	/**
	 * 缩小用时
	 */
	private int durationSmall;
	/**
	 * 滑动用时
	 */
	private int durationTranslate;
	/**
	 * 触发延迟
	 */
	private int delay;
	/**
	 * 光标边框宽度 包括阴影
	 */
	private int boarder;
	/**
	 * 光标左边框宽度 含阴影
	 */
	private int boarderLeft;
	/**
	 * 光标顶边框宽度 含阴影
	 */
	private int boarderTop;
	/**
	 * 光标右边框宽度 含阴影
	 */
	private int boarderRight;
	/**
	 * 光标底边框宽度 含阴影
	 */
	private int boarderBottom;

	private int paddingLeft, paddingTop;

	private boolean initFlag = true;
	/**
	 * 焦点离开容器
	 */
	private boolean focusIsOut;

	/**
	 * 是否初始化焦点
	 */
	private boolean initFocus;

	public boolean isInitFocus() {
		return initFocus;
	}

	public void setInitFocus(boolean initFocus) {
		this.initFocus = initFocus;
	}

	private AnimatorSet animatorSet;
	private ObjectAnimator largeX;

	private OnChildSelectListener onChildSelectListener;
	private OnChildClickListener onChildClickListener;

	public int getCursorRes() {
		return cursorRes;
	}

	public void setCursorRes(int cursorRes) {
		this.cursorRes = cursorRes;
	}

	public void setCursorResMultiDisplay(int cursorRes_1280,
			int cursorRes_1920, int cursorRes_2560, int cursorRes_3840) {

		switch (getResources().getDisplayMetrics().widthPixels) {
		case TvUtil.SCREEN_1280:
			cursorRes = cursorRes_1280;
			break;

		case TvUtil.SCREEN_1920:
			cursorRes = cursorRes_1920;
			break;
		case TvUtil.SCREEN_2560:
			cursorRes = cursorRes_2560;
			break;
		case TvUtil.SCREEN_3840:
			cursorRes = cursorRes_3840;
			break;
		}
	}

	public boolean isScalable() {
		return scalable;
	}

	public void setScalable(boolean scalable) {
		this.scalable = scalable;
	}

	public float getScale() {
		return scale;
	}

	public void setScale(float scale) {
		this.scale = scale;
	}

	public int getDelay() {
		return delay;
	}

	public void setDelay(int delay) {
		this.delay = delay;
	}

	public void setBoarder(int boarderLeft, int boarderTop, int boarderRight,
			int boarderBottom) {
		this.boarderLeft = boarderLeft;
		this.boarderTop = boarderTop;
		this.boarderRight = boarderRight;
		this.boarderBottom = boarderBottom;
	}

	public int getBoarderLeft() {
		return boarderLeft;
	}

	public int getBoarderTop() {
		return boarderTop;
	}

	public int getBoarderRight() {
		return boarderRight;
	}

	public int getBoarderBottom() {
		return boarderBottom;
	}

	public TvRelativeLayoutAsGroup(Context context) {
		this(context, null);
	}

	public TvRelativeLayoutAsGroup(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public TvRelativeLayoutAsGroup(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);
		TypedArray custom = getContext().obtainStyledAttributes(attrs,
				R.styleable.TvRelativeLayoutAsGroup);

		this.initFocus = custom.getBoolean(
				R.styleable.TvRelativeLayoutAsGroup_initFocus, true);
		this.cursorRes = custom.getResourceId(
				R.styleable.TvRelativeLayoutAsGroup_cursorRes, 0);
		this.scalable = custom.getBoolean(
				R.styleable.TvRelativeLayoutAsGroup_scalable, true);
		this.scale = custom.getFloat(R.styleable.TvRelativeLayoutAsGroup_scale,
				1.1f);
		this.animationType = custom.getInt(
				R.styleable.TvRelativeLayoutAsGroup_animationType, 0);
		this.delay = custom.getInteger(
				R.styleable.TvRelativeLayoutAsGroup_delay, 110);
		this.durationLarge = custom.getInteger(
				R.styleable.TvRelativeLayoutAsGroup_durationLarge, 100);
		this.durationSmall = custom.getInteger(
				R.styleable.TvRelativeLayoutAsGroup_durationSmall, 100);
		this.durationTranslate = custom.getInteger(
				R.styleable.TvRelativeLayoutAsGroup_durationTranslate, 9);
		this.boarder = (int) custom.getDimension(
				R.styleable.TvRelativeLayoutAsGroup_boarder, 0)
				+ custom.getInteger(
						R.styleable.TvRelativeLayoutAsGroup_boarderInt, 0);

		if (boarder == 0) {
			this.boarderLeft = (int) custom.getDimension(
					R.styleable.TvRelativeLayoutAsGroup_boarderLeft, 0)
					+ custom.getInteger(
							R.styleable.TvRelativeLayoutAsGroup_boarderLeftInt,
							0);
			this.boarderTop = (int) custom.getDimension(
					R.styleable.TvRelativeLayoutAsGroup_boarderTop, 0)
					+ custom.getInteger(
							R.styleable.TvRelativeLayoutAsGroup_boarderTopInt,
							0);
			this.boarderRight = (int) custom.getDimension(
					R.styleable.TvRelativeLayoutAsGroup_boarderRight, 0)
					+ custom.getInteger(
							R.styleable.TvRelativeLayoutAsGroup_boarderRightInt,
							0);
			this.boarderBottom = (int) custom.getDimension(
					R.styleable.TvRelativeLayoutAsGroup_boarderBottom, 0)
					+ custom.getInteger(
							R.styleable.TvRelativeLayoutAsGroup_boarderBottomInt,
							0);
		} else {
			this.boarderLeft = boarder;
			this.boarderTop = boarder;
			this.boarderRight = boarder;
			this.boarderBottom = boarder;
		}

		if (cursorRes == 0) {
			switch (getResources().getDisplayMetrics().widthPixels) {
			case TvUtil.SCREEN_1280:
				cursorRes = custom.getResourceId(
						R.styleable.TvRelativeLayoutAsGroup_cursorRes_1280, 0);
				break;

			case TvUtil.SCREEN_1920:
				cursorRes = custom.getResourceId(
						R.styleable.TvRelativeLayoutAsGroup_cursorRes_1920, 0);
				break;
			case TvUtil.SCREEN_2560:
				cursorRes = custom.getResourceId(
						R.styleable.TvRelativeLayoutAsGroup_cursorRes_2560, 0);
				break;
			case TvUtil.SCREEN_3840:
				cursorRes = custom.getResourceId(
						R.styleable.TvRelativeLayoutAsGroup_cursorRes_3840, 0);
				break;
			case TvUtil.SCREEN_4096:
				cursorRes = custom.getResourceId(
						R.styleable.TvRelativeLayoutAsGroup_cursorRes_4096, 0);
				break;
			}
		}

		custom.recycle();

		// 关闭子控件动画缓存 使嵌套动画更流畅
		setAnimationCacheEnabled(false);

		init();

	}

	private void init() {
		focusIsOut = true;
	}

	@Override
	public boolean dispatchKeyEventPreIme(KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_DOWN) {
			int direction = 0;
			switch (event.getKeyCode()) {
			case KeyEvent.KEYCODE_DPAD_DOWN:
				direction = View.FOCUS_DOWN;
				break;
			case KeyEvent.KEYCODE_DPAD_RIGHT:
				direction = View.FOCUS_RIGHT;
				break;
			case KeyEvent.KEYCODE_DPAD_UP:
				direction = View.FOCUS_UP;
				break;
			case KeyEvent.KEYCODE_DPAD_LEFT:
				direction = View.FOCUS_LEFT;
				break;
			}
			View focus = findFocus();

			if (focus != null && direction != 0) {

				View next = focus.focusSearch(direction);

				if (next != null) {
					focusIsOut = false;
				} else {
					focusIsOut = true;
				}

			}

		}

		return super.dispatchKeyEventPreIme(event);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		for (int i = 0; i < getChildCount(); i++) {
			View item = getChildAt(i);

			if (item.getTag() != null
					&& item.getTag().toString().equals(cursorTag)) {

				continue;
			}

			measureChild(item, widthMeasureSpec, heightMeasureSpec);

			RelativeLayout.LayoutParams rlp = (LayoutParams) item
					.getLayoutParams();
			rlp.width = item.getMeasuredWidth();
			rlp.height = item.getMeasuredHeight();
		}

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {

		// Log.e(VIEW_LOG_TAG, "onLayout");
		if (changed) {
			super.onLayout(changed, l, t, r, b);
		} else {
			int cCount = getChildCount();
			int cWidth = 0;
			int cHeight = 0;
			MarginLayoutParams cParams = null;
			/**
			 * 遍历所有childView根据其宽和高，以及margin进行布局 选中框无需重定位??初始位置
			 */
			for (int i = 0; i < cCount; i++) {
				View childView = getChildAt(i);

				if (childView.getTag() != null
						&& childView.getTag().toString().equals(cursorTag)) {
					continue;
				}

				cWidth = childView.getMeasuredWidth();
				cHeight = childView.getMeasuredHeight();
				cParams = (MarginLayoutParams) childView.getLayoutParams();

				int cl = 0, ct = 0, cr = 0, cb = 0;

				cl = childView.getLeft();
				ct = childView.getTop();
				cr = cl + cWidth;
				cb = cHeight + ct;
				childView.layout(cl, ct, cr, cb);
			}
		}

	}

	@Override
	protected void onAttachedToWindow() {
		bindEvent();
		super.onAttachedToWindow();
	}

	// 初始化焦点
	private void bindEvent() {

		if (getChildCount() < 1) {
			return;
		}
		initFlag = false;
		View child = null;
		for (int i = 0; i < getChildCount(); i++) {

			child = getChildAt(i);

			if (child != null) {
				child.setOnFocusChangeListener(new OnFocusChangeListener() {

					@Override
					public void onFocusChange(final View child, boolean focus) {
						if (focus) {

							new Handler().postDelayed(new Runnable() {

								@Override
								public void run() {
									moveCover(child);
								}
							}, delay);
							// 选中事件
							if (onChildSelectListener != null) {
								onChildSelectListener.onChildSelect(child);
							}

						} else {
							returnCover(child);
						}
					}
				});

				if (onChildClickListener != null) {
					child.setOnClickListener(new OnClickListener() {

						@Override
						public void onClick(View child) {
							onChildClickListener.onChildClick(child);

						}
					});
				}

			}
		}

		// 初始化焦点
		final View focus = findFocus();
		if (focus != null && initFocus) {

			new Handler().postDelayed(new Runnable() {

				@Override
				public void run() {
					focus.requestFocus();
					moveCover(focus);
				}
			}, 300);

		}

	}

	/**
	 * 光标移动 到达后 与控件同时放大
	 */
	private void moveCover(View item) {
		if (cursor == null) {
			cursor = new View(getContext());
			cursor.setTag(cursorTag);
			cursor.setBackgroundResource(cursorRes);
			this.addView(cursor);
		}
		setBorderParams(item);

	}

	/**
	 * 还原控件状态
	 */

	private void returnCover(View item) {
		if (cursor == null) {
			return;
		}
		cursor.setVisibility(View.INVISIBLE);
		if (scalable) {
			scaleToNormal(item);
		}
	}

	private void scaleToLarge(View item) {

		if (!item.isFocused()) {
			return;
		}

		animatorSet = new AnimatorSet();
		largeX = ObjectAnimator.ofFloat(item, "ScaleX", 1f, scale);
		ObjectAnimator largeY = ObjectAnimator.ofFloat(item, "ScaleY", 1f,
				scale);
		ObjectAnimator cursorX = ObjectAnimator.ofFloat(cursor, "ScaleX", 1f,
				scale);
		ObjectAnimator cursorY = ObjectAnimator.ofFloat(cursor, "ScaleY", 1f,
				scale);

		animatorSet.setDuration(durationLarge);
		animatorSet.play(largeX).with(largeY).with(cursorX).with(cursorY);

		animatorSet.start();
	}

	private void scaleToNormal(View item) {
		if (animatorSet == null) {
			return;
		}
		if (animatorSet.isRunning()) {
			animatorSet.cancel();
		}
		ObjectAnimator oa = ObjectAnimator.ofFloat(item, "ScaleX", 1f);
		oa.setDuration(durationSmall);
		oa.start();
		ObjectAnimator oa2 = ObjectAnimator.ofFloat(item, "ScaleY", 1f);
		oa2.setDuration(durationSmall);
		oa2.start();
	}

	/**
	 * 指定光标相对位置
	 */
	private void setBorderParams(View item) {
		cursor.clearAnimation();
		cursor.setVisibility(View.VISIBLE);

		// 判断类型
		RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) item
				.getLayoutParams();
		final int l = item.getLeft() - boarderLeft;
		final int t = item.getTop() - boarderTop;
		final int r = item.getLeft() + params.width + boarderRight;
		final int b = item.getTop() + params.height + boarderBottom;

		switch (animationType) {
		case ANIM_DEFAULT:
			cursor.layout(l, t, r, b);
			item.bringToFront();
			cursor.bringToFront();
			if (scalable) {
				scaleToLarge(item);
			}
			break;
		case ANIM_TRASLATE:
			if (cursor.getLeft() <= 0) {
				cursor.layout(l, t, r, b);
			}

			item.bringToFront();
			cursor.bringToFront();

			// if (focusIsOut) {
			// return;
			// }

			// Log.e(VIEW_LOG_TAG, l + "--" + t + "--" + r + "--" + b);
			TvAnimator animator = new TvAnimator(cursor, item);
			animator.setTargetParams(l, t, r - l, b - t);
			animator.execute();

			break;

		}

	}

	class TvAnimator extends AsyncTask<Void, Integer, Integer> {
		private View target, item;
		private int l, t, cl, ct;
		private int width, cwidth, height, cheight;
		private int dX, dY, dW, dH;
		private int frequence = 17;

		TvAnimator(View target, View item) {
			this.target = target;
			this.item = item;
		}

		public void setTargetParams(int l, int t, int width, int height) {
			this.l = l;
			this.t = t;
			this.width = width;
			this.height = height;
			this.cl = target.getLeft();
			this.ct = target.getTop();
			this.cwidth = target.getWidth();
			this.cheight = target.getHeight();
		}

		/** 
         * 
         */
		@Override
		protected void onPreExecute() {

			dW = (int) (width - cwidth > 0 ? Math.ceil((width - cwidth)
					/ (frequence * 1.0)) : Math.floor((width - cwidth)
					/ (frequence * 1.0)));
			dH = (int) (height - cheight > 0 ? Math.ceil((height - cheight)
					/ (frequence * 1.0)) : Math.floor((height - cheight)
					/ (frequence * 1.0)));
			dX = (int) (l - cl > 0 ? Math.ceil((l - cl) / (frequence * 1.0))
					: Math.floor((l - cl) / (frequence * 1.0)));
			dY = (int) (t - ct >= 0 ? Math.ceil((t - ct) / (frequence * 1.0))
					: Math.floor((t - ct) / (frequence * 1.0)));

			// Log.e(VIEW_LOG_TAG, cl + "---" + l + "---" + ct + "---" + t
			// + "====" + dX + ":" + dY + ":" + dW + ":" + dH + "---"
			// +durationTranslate);
		}

		/** 
         * 
         */
		@Override
		protected Integer doInBackground(Void... params) {

			while (cl != l || t != ct || cwidth != width || cheight != height) {

				if (Math.abs(cl - l) <= Math.abs(dX)) {
					cl = l;
				} else {
					cl += dX;
				}

				if (Math.abs(ct - t) <= Math.abs(dY)) {
					ct = t;
				} else {
					ct += dY;
				}

				if (Math.abs(width - cwidth) <= Math.abs(dW)) {
					cwidth = width;
					dW = 0;
				} else {
					cwidth += dW;
				}

				if (Math.abs(height - cheight) <= Math.abs(dH)) {
					cheight = height;
					dH = 0;
				} else {
					cheight += dH;
				}

				// Log.e(VIEW_LOG_TAG, cl+"=="+ct+"=="+(cl + cwidth +
				// dW)+"=="+(ct + cheight + dH));

				publishProgress(cl, ct, cl + cwidth + dW, ct + cheight + dH);
				try {
					Thread.sleep(durationTranslate);
				} catch (InterruptedException e) {
				}
			}

			return null;
		}

		/** 
         * 
         */
		@Override
		protected void onPostExecute(Integer integer) {
			if (scalable) {
				if (!item.isFocused()) {
					return;
				}

				animatorSet = new AnimatorSet();
				ValueAnimator largeX = ObjectAnimator.ofFloat(item, "ScaleX",
						1f, scale);
				ValueAnimator largeY = ObjectAnimator.ofFloat(item, "ScaleY",
						1f, scale);

				animatorSet.setDuration(durationLarge);
				animatorSet.setInterpolator(new DecelerateInterpolator(3.0f));
				animatorSet.play(largeX).with(largeY);
				animatorSet.start();
				// 中心放大 左上减 右下加
				ValueAnimator animation = ValueAnimator.ofFloat(1f, scale);
				animation.setDuration(durationLarge);
				animation.setInterpolator(new DecelerateInterpolator(3.0f));
				animation.addUpdateListener(new AnimatorUpdateListener() {
					@Override
					public void onAnimationUpdate(ValueAnimator animation) {
						// Log.i("update", ((Float)
						// animation.getAnimatedValue())
						// .toString());
						float curScale = (Float) animation.getAnimatedValue();

						int dw = (int) (width * (curScale - 1) / 2);
						int dh = (int) (height * (curScale - 1) / 2);

						target.layout(l - dw, t - dh, l + width + dw, t
								+ height + dh);
					}
				});
				animation.start();

			}

		}

		/** 
         * 
         */
		@Override
		protected void onProgressUpdate(Integer... values) {
			target.layout(values[0], values[1], values[2], values[3]);
		}
	}

	public void setOnChildSelectListener(OnChildSelectListener myListener) {
		this.onChildSelectListener = myListener;
	}

	public void setOnChildClickListener(OnChildClickListener myListener) {
		this.onChildClickListener = myListener;
	}

	public interface OnChildSelectListener {
		public void onChildSelect(View child);
	}

	public interface OnChildClickListener {
		public void onChildClick(View child);
	}

}
